package com.iims.flowable.controller;


import cn.hutool.core.codec.Base64;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.iims.common.annotation.Log;
import com.iims.common.core.domain.AjaxResult;
import com.iims.common.core.page.TableDataInfo;
import com.iims.common.enums.BusinessType;
import com.iims.common.exception.CustomException;
import com.iims.flowable.common.constant.FlowableConstant;
import com.iims.flowable.common.enums.FlowActiveEnum;
import com.iims.flowable.factory.BaseFlowableController;
import com.iims.flowable.flow.domain.FlowBusinessHistory;
import com.iims.flowable.flow.vo.CommentResponse;
import com.iims.flowable.flow.vo.ExecuteTaskDataVo;
import com.iims.flowable.flow.vo.ProcessInstanceRequest;
import com.iims.flowable.flow.vo.request.*;
import com.iims.flowable.flow.vo.resp.FlowMyProcessInstanceDto;
import com.iims.flowable.flow.vo.resp.ProcessInsDetailResponse;
import com.iims.flowable.flow.vo.wrapper.WrapperFlowCommentList;
import com.iims.flowable.flow.vo.wrapper.WrapperFlowTaskStartList;
import com.iims.flowable.service.IFlowInstanceService;
import com.iims.flowable.service.IFlowTaskImageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.query.QueryProperty;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.HistoricProcessInstanceQueryProperty;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.service.impl.HistoricTaskInstanceQueryProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>工作流流程实例管理<p>
 *
 * @author fanpei
 * @date 2021-04-03
 */
@Slf4j
@Api(tags = "流程实例")
@ApiSort(3)
@RestController
@RequestMapping("/flowable/instance")
public class FlowInstanceController extends BaseFlowableController {

    @Autowired
    private IFlowInstanceService flowInstanceService;

    @Autowired
    private IFlowTaskImageService flowTaskImageService;


    public static final Map<String, QueryProperty> allowedSortProperties = new HashMap<>();

    static {
        allowedSortProperties.put(FlowableConstant.ID, HistoricProcessInstanceQueryProperty.PROCESS_INSTANCE_ID_);
        allowedSortProperties.put(FlowableConstant.PROCESS_DEFINITION_ID, HistoricProcessInstanceQueryProperty.PROCESS_DEFINITION_ID);
        allowedSortProperties.put(FlowableConstant.PROCESS_DEFINITION_KEY, HistoricProcessInstanceQueryProperty.PROCESS_DEFINITION_KEY);
        allowedSortProperties.put(FlowableConstant.BUSINESS_KEY, HistoricProcessInstanceQueryProperty.BUSINESS_KEY);
        allowedSortProperties.put("startTime", HistoricProcessInstanceQueryProperty.START_TIME);
        allowedSortProperties.put("endTime", HistoricProcessInstanceQueryProperty.END_TIME);
        allowedSortProperties.put("duration", HistoricProcessInstanceQueryProperty.DURATION);
        allowedSortProperties.put(FlowableConstant.TENANT_ID, HistoricProcessInstanceQueryProperty.TENANT_ID);
    }


    @ApiOperation(value = "我的任务", notes = "个人发起的全部流程", response = FlowMyProcessInstanceDto.class)
    @ApiOperationSupport(order = 1, ignoreParameters = {"orderByColumn", "isAsc"})
    @GetMapping(value = "/listStartedByMe")
    public TableDataInfo listStartedByMe(FlowStartCCtoMeQueryVo taskQueryVo) throws Exception {
        // taskQueryVo.setPageDomain(getPageDomain());
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        return this.pageList(taskQueryVo, query, WrapperFlowTaskStartList.class, allowedSortProperties, HistoricTaskInstanceQueryProperty.START);
    }


    @ApiOperation(value = "抄送给我", notes = "别人抄送给我的", response = FlowMyProcessInstanceDto.class)
    @ApiOperationSupport(order = 2, ignoreParameters = {"orderByColumn", "isAsc"})
    @GetMapping(value = "/listCcToMe")
    public TableDataInfo listCcToMe(FlowStartCCtoMeQueryVo taskQueryVo) throws Exception {
        taskQueryVo.setCcToMe(true);
        //taskQueryVo.setPageDomain(getPageDomain());
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        return this.pageList(taskQueryVo, query, WrapperFlowTaskStartList.class, allowedSortProperties, HistoricTaskInstanceQueryProperty.START);
    }

    @ApiOperation(value = "指定业务数据关联流程记录", response = FlowMyProcessInstanceDto.class)
    @ApiOperationSupport(order = 3, ignoreParameters = {"orderByColumn", "isAsc"})
    @GetMapping(value = "/listBusinessHis")
    public TableDataInfo listBusinessHistory(FlowBusinessHistoryQuery historyQuery) throws Exception {
        //historyQuery.setPageDomain(getPageDomain());
        FlowBusinessHistory flowBusinessHistory = flowBusinessUtils.selectOneFlowBusinessHis(historyQuery.getFlowBusinessType(), historyQuery.getTargetBusinessId());
        historyQuery.setBusinessKey(flowBusinessHistory.getFlowBusinessKey());
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        return this.pageList(historyQuery, query, WrapperFlowTaskStartList.class, allowedSortProperties, HistoricTaskInstanceQueryProperty.START);
    }

    //暂时无用 弃用日期 2021-06-27
    //@ApiOperation(value = "我涉及流程汇总信息", response = CategoryVo.class)
    //@ApiOperationSupport(order = 3)
    //@GetMapping(value = "/listMyInvolvedSummary")
    @Deprecated
    public AjaxResult listMyInvolvedSummary(FlowSummaryQueryVo flowSummaryQueryVo) {
        flowSummaryQueryVo.setUserId(getLoginUserCode());
        return AjaxResult.success(this.flowInstanceService.listMyInvolvedSummary(flowSummaryQueryVo));
    }

    @ApiOperation(value = "指定流程实例详情", response = ProcessInsDetailResponse.class)
    @ApiOperationSupport(order = 4)
    @GetMapping(value = "/queryById/{processInstanceId}")
    public AjaxResult queryById(@ApiParam(value = "流程实例Id", required = true) @PathVariable String processInstanceId) {
        permissionService.validateReadPermissionOnProcessInstance(getLoginUserCode(), processInstanceId);
        ProcessInstance processInstance = null;
        HistoricProcessInstance historicProcessInstance = flowInstanceService.getHistoricProcessInstanceById(processInstanceId);
        if (historicProcessInstance.getEndTime() == null) {
            //正在运行实例
            processInstance = flowInstanceService.getProcessInstanceById(processInstanceId);
        }
        return AjaxResult.success(responseFactory.createProcessInsDetail(historicProcessInstance, processInstance));
    }

    @ApiOperation(value = "获取流程执行表单数据(历史)", response = ExecuteTaskDataVo.class)
    @ApiOperationSupport(order = 5)
    @GetMapping(value = "/executeTaskData/{processInstanceId}")
    public AjaxResult executeTaskData(@ApiParam(value = "流程实例Id", required = true) @PathVariable String processInstanceId) {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (null == processInstance)
            throw new CustomException("流程任务ProcessInstanceId:" + processInstanceId + "不存在");

        ExecuteTaskDataVo executeTaskDataVo = new ExecuteTaskDataVo();
        executeTaskDataVo.setStartUserId(processInstance.getStartUserId());

        //获取起始任务数据表单
        initStartDataFormBack(
                processInstance.getProcessDefinitionId(), processInstance.getProcessDefinitionKey(),
                processInstanceId, processInstance.getBusinessKey(), executeTaskDataVo);

        // executeTaskDataVo.setVariables(variables);

        //获取历史表单
        executeTaskDataVo.setHistoryTaskForms(cmisTaskFormService.getRenderedTaskForms(processInstanceId));
        return AjaxResult.success(executeTaskDataVo);
    }

    @ApiOperation(value = "指定流程实例过程记录", response = CommentResponse.class)
    @ApiOperationSupport(order = 6)
    @GetMapping(value = "/comments/{processInstanceId}")
    public AjaxResult comments(@ApiParam(value = "流程实例Id", required = true) @PathVariable String processInstanceId) {
        permissionService.validateReadPermissionOnProcessInstance(this.getLoginUserCode(), processInstanceId);
        List<Comment> datas = taskService.getProcessInstanceComments(processInstanceId);
        Collections.reverse(datas);
        return AjaxResult.success(this.listWrapper(WrapperFlowCommentList.class, datas));
    }

    @ApiOperation("指定流程实例过程执行图")
    @ApiOperationSupport(order = 7)
    @GetMapping("/diagram/{processInstanceId}")
    public AjaxResult genProcessDiagram(@ApiParam(value = "流程实例id") @PathVariable String processInstanceId, HttpServletResponse response) {
        //sendImageStream(response, flowTaskImageService.diagram(processInstanceId));
        return AjaxResult.success("流程图获取成功", Base64.encode(flowTaskImageService.diagram(processInstanceId)));
    }

    @ApiOperation(value = "启动流程")
    @ApiOperationSupport(order = 8)
    @Log(title = "启动流程", businessType = BusinessType.START)
    @PostMapping("/start")
    public AjaxResult startById(@Validated @RequestBody ProcessInstanceRequest processInstanceRequest) {
        flowInstanceService.start(processInstanceRequest);
        return AjaxResult.success("启动流程成功");
    }

    @ApiOperation(value = "激活或挂起")
    @ApiOperationSupport(order = 9, ignoreParameters = {"processDefinitionId", "includeProcessInstances"})
    @Log(title = "激活或挂起流程实例", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('flowable:processInstance:suspendOrActivate')")
    @PostMapping(value = "/updateState")
    public AjaxResult updateState(@RequestBody FlowActiveSuspendRequest activeSuspendQueryVo) {
        if (FlowActiveEnum.ACTIVE.getValue() == activeSuspendQueryVo.getStatus()) {
            flowInstanceService.activate(activeSuspendQueryVo.getProcessInstanceId());
        } else {
            flowInstanceService.suspend(activeSuspendQueryVo.getProcessInstanceId());
        }
        return AjaxResult.success();
    }


    @ApiOperation(value = "删除流程实例")
    @ApiOperationSupport(order = 10, ignoreParameters = "processDefinitionId")
    @Log(title = "删除流程实例", businessType = BusinessType.DELETE)
    @PreAuthorize("@ss.hasPermi('flowable:processInstance:delete')")
    @DeleteMapping(value = "/delete")
    public AjaxResult delete(@RequestBody FlowDeleteRequest flowDeleteQueryVo) {
        flowInstanceService.delete(flowDeleteQueryVo.getProcessInstanceId(), flowDeleteQueryVo.getCascade(), flowDeleteQueryVo.getDeleteReason());
        return AjaxResult.success();
    }
}